
#include "stdlib.h"
#include "string.h"
#include "stdarg.h"
#include "FreeRTOS.h"
#include "task.h"
#include "stm32f1xx_hal.h"

#include "wifi-ops.h"

#define	RTBUF_SIZE	128

/*when esp recv data from serv,whatever ap or station will call it in intr
 * attation:cb be called intr,can not exec sleep action , means cannot send data to serv
 * */
esp_callback_t  esp_callback  = NULL;

/*
how to use it:

	esp use uart3 idle intr,firs of all,you must define callback fun  int main.c
	####attation###: uart3 intr must set  Usr FreeRTOS

		void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
		{
			//other thing to do
			wifi_uart_prepare_idle(huart);		//after recv success, wo must prepare uart for next time
		}


	 AP mode ,
		wifi_uart_prepare_idle			#for uart recv idle data

		wifi_ap_init(	callback)			##esp step into ap mode
		wifi_ap_set_args				##set ap name and passwd
		wifi_ap_tcp_listen_and_wait_connect_timeout		##wait for phone connect to ap
		while(1){
			##wifi_ap_tcp_wait_recvdata_timeout			## on be conneted, wait for phone'data
			### 也可以不用上面函数,有了数据会执行callback
			wifi_ap_tcp_send_data						## on got data from phone,send response to phone
		}
		
		
		## attention:this api ,when from ap to station,have to reboot (wifi_modue_force_reset)
			or esp will no response for any at;
			I have add reset fun at  station_init

	station:
		wifi_uart_prepare_idle

		wifi_station_init (callback)
		wifi_station_join_ap
		wifi_station_tcp_connect
		while(1){
			 wifi_station_tcp_send_than_recvdata_timeout
			 	 或者 wifi_station_tcp_send_data,在callback中等待消息.  但要注意同步问题,不要连续发送太快,
			 	 等待送来的消息.
			
		}
*/


/*####### uart base opeartion  ####################*/

#define DEBUG_ENABLE	1		//是否打印调试信息的接口

#define AT_ARGSERR  -551		//发送AT指令中,失败返回原因
#define AT_SENDERR	-552
#define AT_TIMEOUT  -553
#define AT_OK		0

volatile uint8_t at_recvbuf[256];	//esp recv data buf
//we find when task use at_recvbuf,intr may break destroy it ...

volatile  uint8_t at_rxlen;
volatile uint8_t AT_data_ready = 0;	//uart got data,set 1 in idle intr, when wait data set 0

volatile uint8_t real_data_ready=0;	// data come from server/phone , IPD data set 1, wait data set 0
char real_data[128];

void wifi_uart_prepare_idle(UART_HandleTypeDef *huart)	/*#  wifi ops intr need called in  uart idle intr ################*/
{
	//MyPrintF("AT idle:%s\r\n",esp_callback);
	AT_data_ready = 1;			//AT data recevied
	if(strstr(at_recvbuf,"IPD")){
		if(esp_callback){
			char *p=strstr(at_recvbuf,":");
			esp_callback(p+1, strlen(p+1));
			strcpy(real_data,p+1);			//real data stored,for wait data fun
			//printf("wifi_uart_prepare_idle cpy realdata:%s\r\n",real_data);
			real_data_ready = 1;
		}
	}
	HAL_UARTEx_ReceiveToIdle_IT(huart,at_recvbuf,sizeof(at_recvbuf));
	return;
}


/*过滤掉 多余的\r\n,让打印更好看*/
void MyPrintF( const char * format, ... )
{
#if  DEBUG_ENABLE
	char sbuf[128];
	va_list args;
	va_start (args, format);
	vsnprintf (sbuf,128,format, args);
	va_end (args);

	int len = strlen(sbuf);
	len-=3;

	for(int i=0;i<=len;i++){
		if( (sbuf[i]=='\r')  || ( sbuf[i]=='\n') ){
			sbuf[i]=' ';
		}
	}
	printf("%s",sbuf);
#endif
}

int at_send_than_recv_match_timeout(UART_HandleTypeDef *huart,
						      const char *sendbuf,int sendlen,char *recvbuf,
									int recvbuflen,char *matchstr,int timeout)
{
	#define	TIME_PER_IN_MS		1
	int cnt = 0;
	int cmpsize;
	HAL_StatusTypeDef ret;

	if(!huart){	return AT_ARGSERR;}

	timeout = timeout/TIME_PER_IN_MS;
	//start recv data:  clear data flags and wait for serial intr set it
	AT_data_ready = 0;
	memset((void*)at_recvbuf,0,sizeof(at_recvbuf));
	//allow only send no recv
	if(sendbuf && sendlen>0 ){
		MyPrintF("--TX:%s--\r\n",sendbuf);
		UBaseType_t vxx;		//不可分割的一部分
		vxx = portSET_INTERRUPT_MASK_FROM_ISR();
		ret = HAL_UART_Transmit(huart,(uint8_t *)sendbuf,sendlen,sendlen);
		portCLEAR_INTERRUPT_MASK_FROM_ISR(vxx);
		if(ret != HAL_OK){
			return AT_SENDERR;
		}
		//osDelay (10);			//wait for send complete if HAL_UART_Transmit_IT
	}
	//if no need recv,than success
	if(!recvbuf || recvbuflen<=0 || timeout<0 || !matchstr){
		return AT_OK;		//cnt is also equeue 0
	}
	/*
	 * bug: 如果 上述发送完毕,收到AT回应存入buf中. 但是突然又来一个 msg 存入buf,造成数据破坏.
	 * 	主要是因为 AT回应慢,serv 回应快.		如何做:  环形队列吗??
	 * */
	for(cnt = 0;cnt < timeout;cnt++){
		if(  AT_data_ready  == 1  ){
			MyPrintF("--RX:%s--\r\n",at_recvbuf);
			if(strstr( (char *)at_recvbuf, matchstr)){
				break;		//got it ,exit loop
			}
			//MyPrintF("sendrecvfun:fond %s not match with %s\r\n",at_recvbuf,matchstr);
			// here mean at_recvbuf is not this time need,deal it by others
			int at_resp_other_handle(char *at_resp);
			//than wait next resp
			AT_data_ready = 0;	//	不匹配
		}
		osDelay(TIME_PER_IN_MS);
	}

	if(cnt >= timeout){
		MyPrintF("--RX TIMEOUT--\r\n");
		return AT_TIMEOUT;
	}

	/*data have been store int at_recvbuf*/
	cmpsize = recvbuflen > sizeof(at_recvbuf) ? sizeof(at_recvbuf):recvbuflen;
	memcpy(recvbuf,(void*)at_recvbuf,cmpsize);
	return cnt*TIME_PER_IN_MS;		/*return time use in ms*/
}

/*##########	esp ops ##################*/

/*
	强制重启esp,用于完成某些特殊的功能,包括测试
	huart: 通过该串口控制esp
*/
int wifi_modue_force_reset(UART_HandleTypeDef *huart)
{
	int ret;
	char rxbuf[RTBUF_SIZE];
	char *pt_resetcmd = "AT+RST\r\n";
	ret = at_send_than_recv_match_timeout(huart,
				    pt_resetcmd,strlen(pt_resetcmd),rxbuf,sizeof(rxbuf),"OK",3000);	
	osDelay(2000);	//wait reset success
	return 0;
}


int  wifi_module_global_setting(UART_HandleTypeDef *huart)
{
	int ret;
	char *pt_stopSmart = "AT+CWSTOPSMART=0\r\n";
	char *pt_stopAutoConnectAP = "AT+CWAUTOCONN=0\r\n";
	char rxbuf[RTBUF_SIZE];
	
	ret = at_send_than_recv_match_timeout(huart,
				    pt_stopSmart,strlen(pt_stopSmart),rxbuf,sizeof(rxbuf),"OK",1000);	
	ret = at_send_than_recv_match_timeout(huart,
				    pt_stopAutoConnectAP,strlen(pt_stopAutoConnectAP),rxbuf,sizeof(rxbuf),"OK",1000);	

	return 0 ;
}

/*******************************************
			below is wifi station function
********************************************/

/*使模块进入 station模式
		tcp udp 通用   */

int wifi_station_init(UART_HandleTypeDef *huart,esp_callback_t esp_cb)
{
	int ret;
	
	char *pt_ate1 = "ATE0\r\n";				//steup echo for debug
	char *pt_reset = "AT+RST\r\n";
	char *ptcmd = "AT+CWMODE?\r\n";
	char *ptsinglemux_cmd = "AT+CIPMUX=1\r\n";		//attetion,  start=0,..

	char *pt_modecmd = "AT+CWMODE=1\r\n";
	char *pt_closeServcmd = "AT+CIPSERVER=0\r\n";		//如果从ap过来的,需要关闭
	char rxbuf[RTBUF_SIZE] = {0};

	wifi_modue_force_reset(huart);		//########## 重启,方便 AP STA切换
	osDelay(3000);		//刚开机,建议不要立马工作

	wifi_module_global_setting(huart);
	
	ret = at_send_than_recv_match_timeout(huart,
				    ptsinglemux_cmd,strlen(ptsinglemux_cmd),rxbuf,sizeof(pt_closeServcmd),"OK",1500);

	ret = at_send_than_recv_match_timeout(huart,
				    pt_modecmd,strlen(pt_modecmd),rxbuf,sizeof(rxbuf),"OK",3000);	
		
	ret = at_send_than_recv_match_timeout(huart,
				    pt_ate1,strlen(pt_ate1),rxbuf,sizeof(rxbuf),"OK",100);
	


	osDelay(5000);
/*	
	ret = at_send_than_recv_match_timeout(huart,
				    ptcmd,strlen(ptcmd),rxbuf,sizeof(rxbuf),"+CWMODE:1",6000);			//more than 3sec sometimes ...
	if(ret <0){
		char *pt_resetcmd = "AT+RST\r\n";
		
		printf("wifi_station_init send AT+CWMODE?, and get %s ,reset now\n",rxbuf);
		//if no in station mode,than step into station and reset it
		ret = at_send_than_recv_match_timeout(huart,
				     pt_modecmd,strlen(pt_modecmd),rxbuf,sizeof(rxbuf),"OK",800);
		ret = at_send_than_recv_match_timeout(huart,
				    pt_resetcmd,strlen(pt_resetcmd),rxbuf,sizeof(rxbuf),"OK",3000);	
		
		osDelay(3000);	//wait reset success
	}
*/


	ret = wifi_station_disconnect(huart);
	if(0 ){
		return -16;
	}	
	
	ret = wifi_station_exit_ap(huart);
	if(0 ){
		return -18;
	}		
	// in station mode
	esp_callback = esp_cb;

	return 0;
}

/*
	station模式下 进入某个ap热点,可以用来网络连接
		tcp udp通用
*/
int wifi_station_join_ap(UART_HandleTypeDef *huart,	char *apname,char *passwd)
{
	int ret;
	char cmdbuf[RTBUF_SIZE];
	char rxbuf[RTBUF_SIZE];
	
	if(!huart || !apname || !passwd){
		return -12;
	}
#if		0
	/*	加入 ap之前,首先要退出 ap		:	AT+CWQAP  返回  OK	*/
	snprintf(cmdbuf,sizeof(cmdbuf),"AT+CWQAP\r\n");		
	ret = at_send_than_recv_match_timeout(huart,
				  cmdbuf,strlen(cmdbuf),rxbuf,sizeof(rxbuf),"OK",200);
	if(ret < 0){
		return -13;
	}
#endif

	//join ap:  AT+CWJAP="TP-LINK_34C2","HQYJCQ2017"
	snprintf(cmdbuf,sizeof(cmdbuf),"AT+CWJAP=\"%s\",\"%s\"\r\n",apname,passwd);		
	ret = at_send_than_recv_match_timeout(huart,
				  cmdbuf,strlen(cmdbuf),rxbuf,sizeof(rxbuf),"WIFI CONNECTED",15*1000);
	if(ret < 0){
		return -14;
	}

	/*我们测试发现   加入ap之后,需要延迟300ms 才能获取 ip,连接等后续功能  
		否则在 获取ip的时候,会出现busy p
	*/
	osDelay(1500);
	return 0;
}

/*
		向某个服务器发起 tcp 连接请求
*/
int wifi_station_tcp_connect(UART_HandleTypeDef *huart,char *ip,int port)
{
	int ret;
	char cmdbuf[RTBUF_SIZE];
	char rxbuf[RTBUF_SIZE];
	
	if(!huart || !ip || !port){
		return -12;
	}
	
	/*获取本地 ip地址   有可能出现busy p,  这就要重启了*/
	strcpy(cmdbuf,"AT+CIFSR\r\n");
	ret = at_send_than_recv_match_timeout(huart,
		cmdbuf,strlen(cmdbuf),rxbuf,sizeof(rxbuf),"OK",8000);	//有时候返回OK,有时候返回 +CIFSR:
#if  0
	if(ret < 0){
		return -25;
	}
#endif

	//	AT+CIPSTART="TCP","192.168.0.114",1010		返回值 CONNECT  ...  OK  or busy p...
	snprintf(cmdbuf,sizeof(cmdbuf),
		"AT+CIPSTART=0,\"TCP\",\"%s\",%d\r\n",ip,port);					//mux=1
	ret = at_send_than_recv_match_timeout(huart,
				  cmdbuf,strlen(cmdbuf),rxbuf,sizeof(rxbuf),"OK",8000);
	if(ret < 0){
		return ret;
	}
	
	return 0;
}

/*
	向服务器/另一方 发起连接请求,udp的
	这里其实就是esp保存 服务器的ip port,供发送的时候使用而已
			peer_ip: 		对方的ip
			local_ip:		esp自己的端口号
*/
int wifi_station_udp_connect(UART_HandleTypeDef *huart,
								char *peer_ip,short peer_port,short local_port)
{
	int ret;
	char cmdbuf[RTBUF_SIZE];
	char rxbuf[RTBUF_SIZE];
	char *ptCloseOtherLink = "AP+CIPCLOSE\r\n";
	
	if(!huart || !peer_ip || peer_port<=0  || local_port<=0){
		return -12;
	}
	
	/*获取本地 ip地址*/
	strcpy(cmdbuf,"AT+CIFSR\r\n");
	ret = at_send_than_recv_match_timeout(huart,
						cmdbuf,strlen(cmdbuf),rxbuf,sizeof(rxbuf),"+CIFSR:",8000);
	if(ret < 0){
		return -25;
	}
	
	/*
	连接UDP服务器
			AT+CIPSTART="UDP","192.168.1.34",8080，9050,2
			192.168.1.34是电脑/对方 IP地址,8080是目的端口号，
			9050是本地端口号，2表示远端可变
				//这里的作为station模式的端口号是随机的，所以只填写主机的IP和端口号就可以。
	*/
	//fisrt destroy old link 
	ret = at_send_than_recv_match_timeout(huart,
						ptCloseOtherLink,strlen(ptCloseOtherLink),rxbuf,sizeof(rxbuf),"OK",3*1000);
	
	snprintf(cmdbuf,sizeof(cmdbuf),
		"AT+CIPSTART=\"UDP\",\"%s\",%d,%d,2\r\n",peer_ip,peer_port,local_port);		
	ret = at_send_than_recv_match_timeout(huart,
				  cmdbuf,strlen(cmdbuf),rxbuf,sizeof(rxbuf),"CONNECT",8000);
	if(ret < 0){
		return ret;
	}
	
	return 0;
}


/*	只发送数据,不建议 使用			后面有更高级的函数
一般我们都是使用 服务器应答模式
	即 智能锁发送数据之后 等待回应,一个通信结束
*/
int wifi_station_tcp_send_data(UART_HandleTypeDef *huart,char *sendbuf,int sendlen)
{
	int ret;
	char cmdbuf[RTBUF_SIZE];
	char rxbuf[RTBUF_SIZE*2];
	char *pt_start;
	
	if(!huart || !sendbuf || sendlen <=0  ){
		return -10;
	}
	
	//	AT+CIPSEND=len   模块返回 >, 持续写入len长度的数据即可, 但是有时候需要很久才返回,所以这里等待很久很久
	snprintf(cmdbuf,sizeof(cmdbuf),
		"AT+CIPSEND=0,%d\r\n",sendlen);
	ret = at_send_than_recv_match_timeout(huart,
				     cmdbuf,strlen(cmdbuf),rxbuf,sizeof(rxbuf),">",6*1000);
	if(ret < 0){
		printf("%s-%d ret=%d\n",__func__,__LINE__,ret);
		return -11;
	}
	
	/*attion: when esp recv SEND OK,  the serv data may have comes....
	 * 	so data clear must  prefix,in front of send
	 * */
	real_data_ready = 0;		//表示当前没有收到数据,为等待fun做准备
	memset(real_data,0,sizeof(real_data));

	ret = at_send_than_recv_match_timeout(huart,
				  sendbuf,sendlen,rxbuf,sizeof(rxbuf),"SEND OK",5000);
	if(ret < 0){
		return ret;
	}
	
	return 0;
}


int wifi_station_tcp_wait_data_timeout(UART_HandleTypeDef *huart,char *rxbuf,
														int buflen,int timeout)
{
	timeout = timeout/2;
	while(timeout--){
		if(!real_data_ready){		//需要配合上面的函数使用
			osDelay(2);
			continue;
		}
		strcpy(rxbuf,real_data);
		real_data_ready = 0;
		memset(real_data,0,sizeof(real_data));
		break;
	}
	return !timeout? -AT_TIMEOUT:0;
}

/*
	服务器工作模式是被动的,
	只有当收到 client请求的时候才会 向客户端发送数据, 
	所以当client发送数据 的时候,紧接着就会收到来自服务器的数据
	client发送和接受应该是一起的(要求服务器配合)
*/
int wifi_station_tcp_send_than_recvdata_timeout(UART_HandleTypeDef *huart,
						char *sendbuf,int sendlen,char *recvbuf,int recvlen,int timeout)
{
	int ret;
	char cmdbuf[RTBUF_SIZE];
	char rxbuf[RTBUF_SIZE*2];
	char *pt_start;
	
	if(!huart || !sendbuf || sendlen <=0 ||   RTBUF_SIZE*2 < recvlen){
		return -10;
	}
	
	//	AT+CIPSEND=len   模块返回 >, 持续写入len长度的数据即可, 但是有时候需要很久才返回,所以这里等待很久很久
	snprintf(cmdbuf,sizeof(cmdbuf),
		"AT+CIPSEND=0,%d\r\n",sendlen);		
	ret = at_send_than_recv_match_timeout(huart,
				     cmdbuf,strlen(cmdbuf),rxbuf,sizeof(rxbuf),">",6*1000);
	if(ret < 0){
		printf("%s-%d ret=%d\n",__func__,__LINE__,ret);
		return -11;
	}
	
#if    1					/*IPD:  表示esp接收到数据,是 数据的前缀*/
	ret = at_send_than_recv_match_timeout(huart,
				sendbuf,sendlen,rxbuf,sizeof(rxbuf),"+IPD,",timeout);
	if(ret < 0){
		return -12;
	}

	//拷贝 需要的数据到 参数缓存
	pt_start = strstr(rxbuf,":");
	if(!pt_start){
		return -13;
	}
	pt_start++;
	
	memcpy(recvbuf,pt_start,recvlen);
#endif
	
	return 0;
}

int wifi_station_udp_send_than_recvdata_timeout(UART_HandleTypeDef *huart,
					char *sendbuf,int sendlen,char *rxbuf,int *rxlen,int timeout)
{

	int ret;
	char cmdbuf[RTBUF_SIZE]={0};
	char Lrxbuf[RTBUF_SIZE];
	
	if(!huart || !sendbuf || sendlen <=0 || !rxbuf || !rxlen ){
		return -12;
	}
	
	//	AT+CIPSEND=id,len   模块返回 >, 持续写入len长度的数据即可
	/*注意这里可能有个严重的bug
	发送指令,没有及时返回 > ,下次发送 收到了上次的>, 可能造成严重混乱!!!
		所以这里的延迟很长,一定要成功.
	
	*/
	snprintf(cmdbuf,sizeof(cmdbuf),"AT+CIPSEND=0,%d\r\n",sendlen);		
	ret = at_send_than_recv_match_timeout(huart,
				  cmdbuf,strlen(cmdbuf),rxbuf,sizeof(rxbuf),">",50);
	if(ret < 0){
		return ret;
	}
	
	ret = at_send_than_recv_match_timeout(huart,
				  sendbuf,sendlen,rxbuf,sizeof(rxbuf),"SEND OK",500);
	if(ret < 0){
		return ret;
	}
	
	char *ptrchar;	
	//	+IPD,datalen:content   返回OK
	//	example:		+IPD,14:I am server!
	ret = at_send_than_recv_match_timeout(huart,
				  NULL,0,Lrxbuf,sizeof(Lrxbuf),"+IPD,",timeout);
	if(ret < 0){
		return ret;
	}
	
	//get datalen
	ptrchar = strstr(Lrxbuf,",");
	if(!ptrchar){
		return -14;
	}
	ptrchar++;
	
	*rxlen = atol(ptrchar);
	
	ptrchar = strstr(Lrxbuf,":");
	if(!ptrchar){
		return -16;
	}
	ptrchar++;
	memcpy(rxbuf,ptrchar,*rxlen);
	
	return 0;	
}

int wifi_station_disconnect(UART_HandleTypeDef *huart)
{
	int ret;
	char cmdbuf[RTBUF_SIZE];
	char rxbuf[RTBUF_SIZE];
	
	if(!huart  ){
		return -12;
	}
	
	//	AT+CIPCLOSE  返回 CLOSED OK
	snprintf(cmdbuf,sizeof(cmdbuf),"AT+CIPCLOSE\r\n");		
	ret = at_send_than_recv_match_timeout(huart,
				  cmdbuf,strlen(cmdbuf),rxbuf,sizeof(rxbuf),"OK",200);
	if(ret < 0){
		return ret;
	}
	
	return 0;
}

int wifi_station_exit_ap(UART_HandleTypeDef *huart)
{
	int ret;
	char cmdbuf[RTBUF_SIZE];
	char rxbuf[RTBUF_SIZE];
	
	if(!huart  ){
		return -12;
	}
	
	//	AT+CWQAP  返回  OK
	snprintf(cmdbuf,sizeof(cmdbuf),"AT+CWQAP\r\n");		
	ret = at_send_than_recv_match_timeout(huart,
				  cmdbuf,strlen(cmdbuf),rxbuf,sizeof(rxbuf),"OK",2000);
	if(ret < 0){
		return 0;
	}
	
	return 0;
}


/*################################
		below is ap mode
#################################*/


/*
	esp进入ap模式
*/
int wifi_ap_init(UART_HandleTypeDef *huart, esp_callback_t ap_cb)
{
	int ret;
	char *pt_ate1 = "ATE0\r\n";				//steup echo for debug
	char *pt_CIPINFO = "AT+CIPDINFO=1\r\n";		//when recv udp msg, IPD contain remote ip port
	char *ptcmd = "AT+CWMODE_CUR?\r\n";		
	char *ptsinglemux_cmd = "AT+CIPMUX=1\r\n";  //#######only 1 support ap tcp server ??##########
	char *ptCloseOtherLink = "AP+CIPCLOSE\r\n";
	
	char rxbuf[RTBUF_SIZE];
	
	osDelay(2000);		//刚开机,建议不要立马工作
	
	wifi_module_global_setting(huart);
	
	ret = at_send_than_recv_match_timeout(huart,
				    pt_ate1,strlen(pt_ate1),rxbuf,sizeof(rxbuf),"OK",100);	
	ret = at_send_than_recv_match_timeout(huart,
				    pt_CIPINFO,strlen(pt_CIPINFO),rxbuf,sizeof(rxbuf),"OK",100);	
	ret = at_send_than_recv_match_timeout(huart,
				    ptsinglemux_cmd,strlen(ptsinglemux_cmd),rxbuf,sizeof(rxbuf),"OK",50);
	
	ret = at_send_than_recv_match_timeout(huart,
						ptCloseOtherLink,strlen(ptCloseOtherLink),rxbuf,sizeof(rxbuf),"OK",1*1000);
	
	
	//step1 : check currrent is station mode?
	ret = at_send_than_recv_match_timeout(huart,
				    ptcmd,strlen(ptcmd),rxbuf,sizeof(rxbuf),"+CWMODE_CUR:2",1000);
	if(ret < 0){
		char *pt_modecmd = "AT+CWMODE_CUR=2\r\n";		//temp change mode, no store in flash
		//char *pt_resetcmd = "AT+RST\r\n";
		
		//if no in station mode,than step into station and reset it
		ret = at_send_than_recv_match_timeout(huart,
				     pt_modecmd,strlen(pt_modecmd),rxbuf,sizeof(rxbuf),"OK",1000);
		//ret = at_send_than_recv_match_timeout(huart,
		//		    pt_resetcmd,strlen(pt_resetcmd),rxbuf,sizeof(rxbuf),"OK",50);	
	}
	if(ap_cb == NULL){
		return -43;
	}
	esp_callback = ap_cb;		//指定回调函数,当 IPD 的时候,中断中会调用
	osDelay(3000);	//wait reset success
	// in ap mode
	return 0;
}

/*
配置ap的 ap热点名字 和密码

*/
int wifi_ap_set_args(UART_HandleTypeDef *huart,
				char *apname,char *passwd)
{

	int ret;
	char cmdbuf[RTBUF_SIZE];
	char rxbuf[RTBUF_SIZE];
	

	if(!huart || !apname || !passwd){
		return -12;
	}
	
	//start/set ap: AT+CWSAP="apname","passwd",6,2
	snprintf(cmdbuf,sizeof(cmdbuf),"AT+CWSAP_CUR=\"%s\",\"%s\",6,2\r\n",apname,passwd);		
	ret = at_send_than_recv_match_timeout(huart,
				  cmdbuf,strlen(cmdbuf),rxbuf,sizeof(rxbuf),"OK",6000);				//here  need more than 3sec 
	if(ret <0){
		return ret;
	}

	return 0;
}


/*  不建议使用该函数, 下面有更高级的函数
		指定ap 模式下tcp的端口 
*/
int wifi_ap_tcp_listen(UART_HandleTypeDef *huart,int port)
{
	int ret;
	char cmdbuf[RTBUF_SIZE];
	char rxbuf[RTBUF_SIZE];
	
	if(!huart  || port <=0){
		return -12;
	}
	
	//	AT+CIPSERVER=1,1111	 返回OK		1-打开服务器模式,1111指定端口
	snprintf(cmdbuf,sizeof(cmdbuf),"AT+CIPSERVER=1,%d\r\n",port);		
	ret = at_send_than_recv_match_timeout(huart,
				  cmdbuf,strlen(cmdbuf),rxbuf,sizeof(rxbuf),"OK",5000);
#if  0	
	if(ret < 0){
		return ret;
	}
#endif
	return 0;
}


/*	return link no	
   不建议使用该函数,  下面有更高级的函数  
*/
int wifi_ap_tcp_waitfor_connect(UART_HandleTypeDef *huart,int timeout)
{
	int ret;
	int linkid;
	char rxbuf[RTBUF_SIZE];
	
	if(!huart ){
		return -12;
	}
	
	//	AT+CIPSERVER=1,1111	 返回OK
	ret = at_send_than_recv_match_timeout(huart,
				  NULL,0,rxbuf,sizeof(rxbuf),"CONNECT",timeout);
	if(ret < 0){
		return ret;
	}
	
	linkid = rxbuf[0] - '0';

	return linkid;
}


/*	return link no	
	建议使用该函数完成上述两个功能
	将监听和等待连接放在一起

	如果成功,返回 客户端linkid,用于和客户端通信
*/
int wifi_ap_tcp_listen_and_wait_connect_timeout
			(UART_HandleTypeDef *huart,int port,int timeout)
{
	int ret;
	
	ret = wifi_ap_tcp_listen(huart,port);
	if(ret <0){
		return -11;
	}

	ret = wifi_ap_tcp_waitfor_connect(huart,timeout);
	if(ret <0){
		return -12;
	}	
	
	return ret;
}



int wifi_ap_tcp_send_data(UART_HandleTypeDef *huart,
								int linkid,char *sendbuf,int sendlen)
{
	int ret;
	char cmdbuf[RTBUF_SIZE];
	char rxbuf[RTBUF_SIZE];
	
	if(!huart || !sendbuf || sendlen <=0 ||linkid <0){
		return -12;
	}
	
	//	AT+CIPSEND=id,len   模块返回 >, 持续写入len长度的数据即可
	snprintf(cmdbuf,sizeof(cmdbuf),
		"AT+CIPSEND=%d,%d\r\n",linkid,sendlen);		
	ret = at_send_than_recv_match_timeout(huart,
				  cmdbuf,strlen(cmdbuf),rxbuf,sizeof(rxbuf),">",20);
	if(ret < 0){
		return ret;
	}
	
	ret = at_send_than_recv_match_timeout(huart,
				  sendbuf,sendlen,rxbuf,sizeof(rxbuf),"SEND OK",500);
	if(ret < 0){
		return ret;
	}
	
	real_data_ready = 0;//	indicate no data ,for wait fun proparae
	memset(real_data,0,sizeof(real_data));

	return 0;
}


/*
	等待指定客户(linkid指定) 发来数据
		ap模式下 接收手机数据,并回应

	这种方式最大的问题是, 只能等待一个 消息
	比如刚发送send,然后收到回应;   对方的推送无法获取的;
*/
int wifi_ap_tcp_wait_recvdata_timeout(UART_HandleTypeDef *huart,
									int linkno,char *rxbuf, int timeout)
{
	while(timeout--){
		if(!real_data_ready){		//需要配合上面的函数使用
			osDelay(1);
			continue;
		}
		strcpy(rxbuf,real_data);
		real_data_ready = 0;
		memset(real_data,0,sizeof(real_data));
		break;
	}
	return !timeout? -AT_TIMEOUT:0;
}




/*
	? ap???, ??esp?????, ?????????
	??cli?????esp, esp???? cli
*/
int wifi_ap_udp_serv_cfg(UART_HandleTypeDef *huart,
					char *cli_ip,short cli_port,short serv_listen_port)
{
	/*
	AT+CIPSTART="UDP","192.168.0.88",8080,9000,0				 0-????  2-????
		192.168.0.88???/??? IP??, esp?????
		8080????(?????/cli)UDP??,
		9000??????( ?ESP8266),0?????? 
	*/
	int ret;
	char cmdbuf[RTBUF_SIZE];
	char rxbuf[RTBUF_SIZE];
	char *ptApIp = "AT+CIPSTATUS\r\n";
	char *ptCloseOtherLink = "AP+CIPCLOSE\r\n";

	if(!huart || !cli_ip || cli_port <=0 ||serv_listen_port <=0){
		return -1112;
	}
	
	//destroy oled link 
	ret = at_send_than_recv_match_timeout(huart,
						ptCloseOtherLink,strlen(ptCloseOtherLink),rxbuf,sizeof(rxbuf),"OK",3*1000);
	snprintf(cmdbuf,sizeof(cmdbuf),
		"AT+CIPSTART=\"UDP\",\"%s\",%d,%d,2\r\n",cli_ip,cli_port,serv_listen_port);		
	ret = at_send_than_recv_match_timeout(huart,
						cmdbuf,strlen(cmdbuf),rxbuf,sizeof(rxbuf),"CONNECT",30*1000);
	if(ret<0){
		return ret;
	}
	
	ret = at_send_than_recv_match_timeout(huart,
				  ptApIp,strlen(ptApIp),rxbuf,sizeof(rxbuf),"+CIPSTATUS",3000);
	printf("%s CIPSTATUS:%s\n",__func__,rxbuf);
	
	return 0;
}

int wifi_ap_udpsend_data(UART_HandleTypeDef *huart,char *sendbuf,int sendlen)
{
	int ret;
	char cmdbuf[RTBUF_SIZE];
	char rxbuf[RTBUF_SIZE];
	
	if(!huart || !sendbuf || sendlen <=0  ){
		return -12;
	}
	
	//udp:	AT+CIPSEND=len,remoteIp,remotePort   
	snprintf(cmdbuf,sizeof(cmdbuf),"AT+CIPSEND=%d\r\n",sendlen);		
	ret = at_send_than_recv_match_timeout(huart,
				  cmdbuf,strlen(cmdbuf),rxbuf,sizeof(rxbuf),">",20);
	if(ret < 0){
		return ret;
	}
	
	ret = at_send_than_recv_match_timeout(huart,
				  sendbuf,sendlen,rxbuf,sizeof(rxbuf),"SEND OK",500);
	if(ret < 0){
		return ret;
	}
	
	return 0;
}


int wifi_ap_udpwait_recvdata_timeout(UART_HandleTypeDef *huart,
									char *rxbuf,int *rxlen,int timeout)
{
	int ret;
	char Lrxbuf[RTBUF_SIZE];
	
	char *ptrchar;
	int Lrxlen;
	
	if(!huart ){
		return -12;
	}

	
	//	+IPD,datalen,remoteIp,remotePOrt:content      	
	//	example:		+IPD,14:I am server!
	ret = at_send_than_recv_match_timeout(huart,
				  NULL,0,Lrxbuf,sizeof(Lrxbuf),"+IPD,",timeout);
	if(ret < 0){
		return ret;
	}
	
	//get datalen
	ptrchar = strstr(Lrxbuf,",");
	if(!ptrchar){
		return -14;
	}
	ptrchar++;
	
	Lrxlen = atol(ptrchar);
	*rxlen = Lrxlen;
	
	ptrchar = strstr(Lrxbuf,":");
	if(!ptrchar){
		return -16;
	}
	ptrchar++;
	memcpy(rxbuf,ptrchar,Lrxlen);
	
	return 0;	
}

/*  ????????  */
int wifi_udp_send_than_recvdata_timeout(UART_HandleTypeDef *huart,
					char *sendbuf,int sendlen,char *rxbuf,int *rxlen,int timeout)
{
	int ret;
	
	ret = wifi_ap_udpsend_data(huart,sendbuf,sendlen);
	if(ret <0){
		return -23;
	}
	
	ret = wifi_ap_udpwait_recvdata_timeout(huart,rxbuf,rxlen, timeout);
	if(ret <0){
		return -24;
	}
	return 0;
}

